﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Runtime.InteropServices;

using System.IO;
using System.Drawing;
using WinHttp;
using System.Net;

using System.Xml;
using System.Diagnostics;

namespace HomeMediaBrowser
{
    /// <summary>
    /// Interaction logic for GoogleLoginPage.xaml
    /// </summary>
    public partial class GoogleLoginPage : PageFunction<String>
    {
        [DllImport("User32.DLL")]
        public static extern int SendMessage(IntPtr hWnd,
            uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("User32.DLL")]
        public static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);

        [DllImport("User32.DLL")]
        public static extern IntPtr LoadImage(IntPtr hInst, IntPtr lpszName, uint uType,
            int cxDesired, int cyDesired, uint fuLoad);

        [DllImport("user32.dll", EntryPoint = "MessageBoxA")]
        static extern int MsgBox(int hWnd, string msg, string caption, int type);

        /// Return Type: LRESULT->LONG_PTR->int
        ///lpUserName: LPCSTR->CHAR*
        ///lpPassword: LPCSTR->CHAR*
        [System.Runtime.InteropServices.DllImportAttribute("GoogleProtocol.dll", EntryPoint = "LogIn")]
       //[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysInt)]
        public static extern int LogIn([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string lpUserName, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string lpPassword);

        /// Return Type: LRESULT->LONG_PTR->int
        ///lpEntryName: LPCSTR->CHAR*
        ///lpIPAddr: LPSTR->CHAR*
        [System.Runtime.InteropServices.DllImportAttribute("GoogleProtocol.dll", EntryPoint = "GetIP")]
        //[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysInt)]
        public static extern int GetIP([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string lpEntryName, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] System.Text.StringBuilder lpIPAddr);

        [System.Runtime.InteropServices.DllImportAttribute("GoogleProtocol.dll", EntryPoint = "GetAccountId")]
        //[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysInt)]
        public static extern int GetAccountId([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] System.Text.StringBuilder lpIPAddr);

        [System.Runtime.InteropServices.DllImportAttribute("GoogleProtocol.dll", EntryPoint = "GetAccountPwd")]
        //[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysInt)]
        public static extern int GetAccountPwd([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] System.Text.StringBuilder lpIPAddr);
        
        /// Return Type: LRESULT->LONG_PTR->int
        [System.Runtime.InteropServices.DllImportAttribute("GoogleProtocol.dll", EntryPoint = "LogOut")]
        //[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysInt)]
        public static extern int LogOut();





        // API ShellExecuteW
        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct HINSTANCE__
        {

            /// int
            public int unused;
        }

        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct HWND__
        {

            /// int
            public int unused;
        }

        public partial class NativeMethods
        {

            /// Return Type: HINSTANCE->HINSTANCE__*
            ///hwnd: HWND->HWND__*
            ///lpOperation: LPCTSTR->LPCWSTR->WCHAR*
            ///lpFile: LPCTSTR->LPCWSTR->WCHAR*
            ///lpParameters: LPCTSTR->LPCWSTR->WCHAR*
            ///lpDirectory: LPCTSTR->LPCWSTR->WCHAR*
            ///nShowCmd: INT->int
            [System.Runtime.InteropServices.DllImportAttribute("shell32.dll", EntryPoint = "ShellExecuteW")]
            public static extern System.IntPtr ShellExecuteW(System.IntPtr hwnd, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPTStr)] string lpOperation, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPTStr)] string lpFile, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPTStr)] string lpParameters, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPTStr)] string lpDirectory, int nShowCmd);

        }

        public GoogleLoginPage()
        {
            InitializeComponent();

            InitPanel();
        }

        public static readonly DependencyProperty NoramlBitmapProperty = DependencyProperty.Register("m_LoginImage", typeof(ImageBrush), typeof(GoogleLoginPage), new FrameworkPropertyMetadata());
        public ImageBrush m_LoginImage
        {
            get { return (ImageBrush)GetValue(NoramlBitmapProperty); }
            set { SetValue(NoramlBitmapProperty, value); }
        }
        public static RoutedEvent LoginEvent = EventManager.RegisterRoutedEvent("LoginEvent", RoutingStrategy.Bubble,
                                                typeof(RoutedEventHandler), typeof(GoogleLoginPage));

        public void SetLogonImage(String strImageFile)
        {
            // why this code does't work?
            ImageBrush imageBrush = new ImageBrush();
            imageBrush.ImageSource = new BitmapImage(new Uri(strImageFile, UriKind.Absolute));
            m_LoginImage = imageBrush;
            // -----

            // Create source.
            BitmapImage bi = new BitmapImage();
            // BitmapImage.UriSource must be in a BeginInit/EndInit block.
            bi.BeginInit();
            bi.UriSource = new Uri(strImageFile, UriKind.RelativeOrAbsolute);
            bi.EndInit();

            ImageBrush_Login_Logo.ImageSource = bi;
        }

        protected void InitWarningIcon()
        {
            Int32 nWarningIconId = 32515; // MAKEINTRESOURCE(IDI_WARNING)
            
            IntPtr hIcon = LoadImage((IntPtr)0, (IntPtr)nWarningIconId, 1/*IMAGE_ICON*/,
                11/*SM_CXICON*/, 12/*SM_CYICON*/, 0x40/*LR_SHARED*/);

            if (hIcon == (IntPtr)0)
            {
                hIcon = LoadIcon((IntPtr)0, (IntPtr)nWarningIconId);
            }

            Icon systemIcon = Icon.FromHandle(hIcon);
            if (systemIcon != null)
            {
                MemoryStream memoryStream = new MemoryStream();
                systemIcon.Save(memoryStream);
                BitmapImage bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = memoryStream;
                bitmapImage.EndInit();
                bitmapImage.Freeze();

                ImageBrush_Warning_Icon.ImageSource = bitmapImage;
            }
        }

        protected void InitLoginLogo()
        {
            SetLogonImage("E:\\Resource\\GoogleAccount.png");
        }

        protected void InitLoadingProgress()
        {
            //LoadinBar = new CircularProgressBar();
            //Progress_Loading.Children.Add(LoadinBar);
        }

        protected CircularProgressBar LoadinBar;
        protected void InitPanel()
        {
            //InitLoginLogo();

            InitWarningIcon();

            InitLoadingProgress();

            m_etyle = ePageStyle.undefined;
            Grid_Warning_Logon_Failed.Visibility = Visibility.Hidden;

            SetLoginStatus(false);

            SetPageTyle(false);
        }

        public void ShowLogonStatus(bool bSucceed)
        {
            Grid_Warning_Logon_Failed.Visibility = bSucceed ? Visibility.Hidden : Visibility.Visible;
            PasswordBox_Password.DataContext = "";
        }

        public string GetUserName()
        {
            return Edit_Account.Text + label_gmail.Content;
        }

        protected string GetPassword()
        {
            //// 使用一个IntPtr类型值来存储加密字符串的起始点   
            //IntPtr p = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(PasswordBox_Password.SecurePassword);

            //// 使用.NET内部算法把IntPtr指向处的字符集合转换成字符串   
            //string password = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(p);
            string password = PasswordBox_Password.Password;

            return password;
        }

        protected bool DllGetServerIP([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] System.Text.StringBuilder lpIPAddr)
        {
            string username = GetUserName();
            string password = GetPassword();

            //-------------------------------------------------------------------
            //  Description:      Login to google server.
            //
            //  Parameter:
            //      lpIPAddr:     Receives server' ip address.
            //      lpUserName:   User Account.
            //      lpPassword:        User Password.
            //
            //  Return:
            //       1            Succeed.
            //       0            Failed.
            //      -1            Http request error;
            //      -2            Authorization error.
            //      -3            Account Id or password error.
            //-------------------------------------------------------------------
            int lResult = LogIn(username, password);
            if (lResult <= 0)
                goto loginerror;

            string strEntryName = "HomeMediaServer";
            StringBuilder strIpAddr = new StringBuilder(128);

            //-------------------------------------------------------------------
            //  Description:      Get server ip address from google contact.
            //
            //  Parameter:
            //      lpEntryName:  Server's name.
            //      lpIPAddr:     Receives server' ip address.
            //
            //  Return:
            //       1            Succeed.
            //       0            Failed.
            //      -1            Http request error;
            //      -2            Authorization error.
            //      -3            Account Id or password error.
            //-------------------------------------------------------------------
            lResult = GetIP(strEntryName, strIpAddr);
            if (lResult <= 0)
                goto loginerror;

            lpIPAddr.Append(strIpAddr);

            //-------------------------------------------------------------------
            //  Description:     Logout from google server.
            //
            //  Parameter:
            //
            //  Return:
            //      1            Succeed.
            //      0            Failed.
            //-------------------------------------------------------------------
            lResult = LogOut();
            return true;

        loginerror:
            return false;
        }

        public static bool SetPublicIP(string ipaddr, string UserName, string Password)
        {
            //1. Login
            //    URL: http://127.0.0.1/server/login?username=xxxxxx&passwd=xxxxxxx
            //    Response Format:
            //    <LoginResponse Status="OK/ERROR" Reason=“xxxxxxxxx"/>
            //    OK表示Login成功，ERROR表示失败。
            //    Reason是失败原因。

            try
            {
                int timeout = 5000;

                string strServerIP = ipaddr;
                string szAuth = "user=";
                szAuth += UserName;
                szAuth += "&";
                szAuth += "passwd=";
                szAuth += Password;

                string URL = strServerIP + "server/login?" + szAuth; // username=xxxxxx&passwd=xxxxxxx
                WinHttpRequestClass WinHttpClass = new WinHttpRequestClass();
                URL = Microsoft.JScript.GlobalObject.encodeURI(URL);
                WinHttpClass.Open("Get", URL, true);
                WinHttpClass.Send(null);
                WinHttpClass.WaitForResponse(timeout);

                string recvStatus = WinHttpClass.ResponseText;

                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(recvStatus);

                XmlElement ele = xmldoc.DocumentElement;

                string errString = ele.GetAttribute("Status");
                bool bOk = errString.CompareTo("OK") == 0;

                return bOk;
            }
            catch (Exception e)
            {
                string err = e.Message;
                return false;
            }
        }
        public bool SetPublicIP(string ipaddr)
        {
            //1. Login
            //    URL: http://127.0.0.1/server/login?username=xxxxxx&passwd=xxxxxxx
            //    Response Format:
            //    <LoginResponse Status="OK/ERROR" Reason=“xxxxxxxxx"/>
            //    OK表示Login成功，ERROR表示失败。
            //    Reason是失败原因。

            try
            {
                int timeout = -1;

                string strServerIP = ipaddr;
                string szAuth = "user=";
                szAuth += GetUserName();
                szAuth += "&";
                szAuth += "passwd=";
                szAuth += GetPassword();

                string URL = strServerIP + "server/login?" + szAuth; // username=xxxxxx&passwd=xxxxxxx
                URL = Microsoft.JScript.GlobalObject.encodeURI(URL);
                WinHttpClass.Open("Get", URL, true);
                WinHttpClass.Send(null);
                WinHttpClass.SetTimeouts(30000, 30000, -1, -1);
                WinHttpClass.WaitForResponse(timeout);

                string recvStatus = WinHttpClass.ResponseText;

                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(recvStatus);

                XmlElement ele = xmldoc.DocumentElement;

                string errString = ele.GetAttribute("Status");
                bool bOk = errString.CompareTo("OK") == 0;

                return bOk;
            }
            catch (Exception e)
            {
                string err = e.Message;
                return false;
            }
        }

        public bool GetPublicIP()
        {             
            // for client, get public ip
            StringBuilder pszPublicIP = new StringBuilder(256);
            bool bResult = DllGetServerIP(pszPublicIP);
            if (!bResult)
            {
                return false;
            }

            m_strServerIP = pszPublicIP.ToString();

            return true;
        }

        protected void SetLoginStatus(bool bLogin)
        {
            //Progress_Loading.Visibility = bLogin ? Visibility.Visible : Visibility.Hidden;
            //if (bLogin)
            //    LoadinBar.StartLoading();
            //else
            //    LoadinBar.StopLoading();

            label_loading.Visibility = bLogin ? Visibility.Visible : Visibility.Hidden;
            Button_Login.IsHitTestVisible = bLogin ? false : true;
            Edit_Account.IsHitTestVisible = bLogin ? false : true;
            PasswordBox_Password.IsHitTestVisible = bLogin ? false : true;
        }

        public void SetPageTyle(bool bServer)
        {
            m_etyle = bServer ? ePageStyle.server : ePageStyle.client;
            LoginTextBlock.Text = bServer ? "Register Your Server" : "Login To Home Media Server";
        }

        private void Button_Login_Click(object sender, RoutedEventArgs e)
        {

            SetLoginStatus(true);
            ShowLogonStatus(true);

            bool bResult = false;

            if (m_etyle == ePageStyle.client)
            {
                bResult = GetPublicIP();
            }
            else if (m_etyle == ePageStyle.server)
            {      
                bResult = SetPublicIP("http://127.0.0.1:8080/");
            }
            else
            {
                // undefined panel style.
                // must be call SetPageTyle in construct function.;
                Debug.Assert(false);
            }

            ShowLogonStatus(bResult);
            SetLoginStatus(false);
            if (bResult)
            {
                RoutedEventArgs args = new RoutedEventArgs();
                args.RoutedEvent = LoginEvent;
                args.Source = this;
                RaiseEvent(args);
            }

        }

        private void Hyperlink_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            IntPtr result = NativeMethods.ShellExecuteW((IntPtr)0, "open", "https://www.google.com/accounts/NewAccount?service=mail", null, null, 1 /* SW_SHOWNORMAL */);

            if ((int)result <= 32)
            {
                // failed
            }
        }

        enum ePageStyle
        { 
            server, 
            client,
            undefined
        };

        public WinHttpRequestClass WinHttpClass = new WinHttpRequestClass();
        public string m_strServerIP;
        ePageStyle m_etyle;
    }
}
